package ext.tianma.changeManager.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import javax.sql.rowset.serial.SerialBlob;

import org.apache.commons.lang.StringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import wt.access.NotAuthorizedException;
import wt.csm.constraint.CSMSingleDefConstraint;
import wt.csm.navigation.CSMClassificationNavigationException;
import wt.csm.navigation.ClassificationNode;
import wt.csm.navigation.litenavigation.ClassificationNodeDefaultView;
import wt.csm.navigation.service.ClassificationHelper;
import wt.csm.navigation.service.ClassificationObjectsFactory;
import wt.fc.Persistable;
import wt.fc.PersistenceHelper;
import wt.fc.QueryResult;
import wt.iba.constraint.FloatContentDiscreteSet;
import wt.iba.constraint.FloatContentRange;
import wt.iba.constraint.IntegerContentDiscreteSet;
import wt.iba.constraint.IntegerContentRange;
import wt.iba.constraint.SingleValued;
import wt.iba.constraint.StringContentDiscreteSet;
import wt.iba.constraint.ValueConstraint;
import wt.iba.constraint.ValueRequired;
import wt.iba.definition.litedefinition.AttributeDefDefaultView;
import wt.iba.value.DefaultAttributeContainer;
import wt.iba.value.IBAHolder;
import wt.inf.container.WTContainerException;
import wt.part.WTPart;
import wt.part.WTPartHelper;
import wt.part.WTPartMaster;
import wt.part.WTPartStandardConfigSpec;
import wt.part.WTPartUsageLink;
import wt.pds.StatementSpec;
import wt.query.QuerySpec;
import wt.query.SearchCondition;
import wt.type.ClientTypedUtility;
import wt.type.TypeDefinitionReference;
import wt.type.TypedUtility;
import wt.util.WTException;
import wt.util.WTPropertyVetoException;
import wt.util.WTRuntimeException;
import wt.util.range.Range;
import wt.vc.views.View;
import wt.vc.views.ViewException;
import wt.vc.views.ViewHelper;

import com.alibaba.fastjson.JSON;
import com.ptc.core.lwc.common.view.AttributeDefinitionReadView;
import com.ptc.core.lwc.common.view.ConstraintDefinitionReadView;
import com.ptc.core.lwc.common.view.EnumerationEntryReadView;
import com.ptc.core.lwc.common.view.GroupDefinitionReadView;
import com.ptc.core.lwc.common.view.GroupMemberView;
import com.ptc.core.lwc.common.view.GroupMembershipReadView;
import com.ptc.core.lwc.common.view.LayoutDefinitionReadView;
import com.ptc.core.lwc.common.view.PropertyValueReadView;
import com.ptc.core.lwc.common.view.ScreenDefinitionReadView;
import com.ptc.core.lwc.common.view.TypeDefinitionReadView;
import com.ptc.core.lwc.server.LWCFilterBasedConstraint;
import com.ptc.core.lwc.server.TypeDefinitionServiceHelper;
import com.ptc.core.meta.common.DiscreteSet;

import ext.com.iba.IBAUtil;
import ext.generic.erp.common.CommonPDMUtil;
import ext.tianma.bom.util.EnumerationUtil;
import ext.tianma.bom.util.LWCUtil;
import ext.tianma.changeManager.constants.ChangeConstants;
import ext.tianma.changeManager.vo.AttrRuleVo;
import ext.tianma.part.finishedProduct.util.CSMUtil;
import ext.tianma.util.TMUtil;

public class ChangeUtil {
	public static final String MSG = "msg";
	public static final String CODE = "code";
	public static final String COUNT = "count";
	public static final String DATA = "data";
	public static final String SUCCESS = "success";
	public static final String CODE_SUCCESS = "200";
	public static final String CODE_FAILED = "0";
	
	public static final String PROP_DISPLAYNAME = "displayName";
	//属性来源：类型上、分类属性
	private static final String [] ATTR_TYPE = {"TypeDefinition","Classification"};
	
	public static final String ATYPE_basic = "basic";
	public static final String ATYPE_model = "model";
	public static final String ATYPE_mapping = "mapping";
	public static final String ATYPE_iba = "iba";
	public static final String ATYPE_ref = "ref";
	
	/**
	 * 返回数据：成功时数据结果集
	 * @param array
	 * @param total
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月3日
	 */
	public static JSONObject resSuccess(JSONArray array, int total) {
		JSONObject result = null;
		try {
			result = respInfo(array, total, "");
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 返回数据：成功时数据条目为空时
	 * @param msg
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月3日
	 */
	public static JSONObject resSuccess0(String msg) {
		JSONObject result = null;
		try {
			result = respInfo(new JSONArray(), 0, msg);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 查询数据时返回接口（特用）
	 * @param dataArray 数据结果集
	 * @param total 数据总数
	 * @param errorMsg 执行时提示信息
	 * @param msg 当数据查询不到时的提示
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月15日
	 */
	public static JSONObject resSuccess(JSONArray dataArray, String errorMsg, String msg) {
		JSONObject result = null;
		if(StringUtils.isNotEmpty(errorMsg)) {
			result = ChangeUtil.resFailed(errorMsg);
		} else {
			if(null != dataArray && dataArray.length() > 0) {
				result = ChangeUtil.resSuccess(dataArray, dataArray.length());
			} else {
				result = ChangeUtil.resSuccess0(msg);
			}
		}
		return result;
	}
	
	/**
	 * 返回信息：成功时提示信息
	 * @param msg
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月3日
	 */
	public static JSONObject resSuccess(String msg) {
		JSONObject result = new JSONObject();
		try {
			result.put(CODE, CODE_SUCCESS);
			result.put(SUCCESS, true);
			result.put(MSG, msg);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 返回信息：失败时提示信息
	 * @param msg
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月10日
	 */
	public static JSONObject resFailed(String msg) {
		JSONObject result = new JSONObject();
		try {
			result.put(CODE, CODE_FAILED);
			result.put(SUCCESS, false);
			result.put(MSG, msg);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 返回信息
	 * @param array 数据内容
	 * @param total 数据总数（不一定是array的条目，有可能是分页）
	 * @param msg 提示信息
	 * @return
	 * @throws JSONException
	 * @author xucr
	 * @CreateDate 2020年11月25日
	 */
	private static JSONObject respInfo(JSONArray array, int total, String msg) throws JSONException {
		JSONObject result = new JSONObject();
		result.put(CODE, CODE_SUCCESS);
    	result.put(SUCCESS, true);
		if(array.length() > 0) {
	    	result.put(COUNT, total);
	    	result.put(DATA, array);
			result.put(MSG, "");
		} else {
			result.put(COUNT, 0);
			result.put(DATA, new JSONArray());
			result.put(MSG, msg);
		}
		return result;
	}
	
	/**
	 * 根据枚举key得到枚举value
	 * @param key
	 * @param enumerName
	 * @return
	 * @author xucr
	 * @CreateDate 2021年1月20日
	 */
	public static String getEnumerValue(String key, String enumerName) {
		String result = "";
		Map<String,String> maps = EnumerationUtil.getEnumerationValues(enumerName);
		if(maps.containsKey(key)) {
			result = maps.get(key);
		}
		return result;
	}
	
	/**
	 * 获取对象上的属性
	 * @param per 对象
	 * @param array
	 * @author xucr
	 * @CreateDate 2020年11月26日
	 */
	public static String initPersistableAttr(Persistable per, JSONArray array, JSONObject changeObj) {
		String tip = "";
		try {
			List<String> ibaNames = Arrays.asList(ChangeConstants.IBANAMES); //这些iba属性key与全局属性名称不一致
			String softType = ChangeUtil.getSoftTypeName(per);
			AttrRuleVo avo = null;
			String beforeValue = "";
			
			//从布局上取属性：指定布局中的属性
			LayoutDefinitionReadView layoutDefinitionReadView = 
					TypeDefinitionServiceHelper.service.getLayoutDefinition(softType, "UPDATE", "Edit Layout");
			if(null != layoutDefinitionReadView) {
				Collection<GroupDefinitionReadView> gdrs = layoutDefinitionReadView.getAllGroups();
				GroupMemberView gm = null;
				AttributeDefinitionReadView av = null;
				String name = "";
				String [] readOnlyAttrs = {"ItemStatus"};//默认只读，不受规则约束
				List<String> attrs = Arrays.asList(readOnlyAttrs);
				for(GroupDefinitionReadView gdr : gdrs) {
					for(GroupMembershipReadView pvr : gdr.getAllMembers()) {
						gm = pvr.getMember();
						name = pvr.getName();
						av = (AttributeDefinitionReadView) gm.getWritableView();
						if(name.indexOf(".") < 0 ){//属性中带.的，不考虑
							avo = new AttrRuleVo();
							String type = attrType(av);
							if(ibaNames.contains(name)) {//特别处理，因为这些IBA属性与全局属性key不对应
								beforeValue = (String) LWCUtil.getValue(per, name);
							} else if(ATYPE_iba.equals(type)) {//IBA属性
								beforeValue = (String) IBAUtil.getIBAValue((IBAHolder) per, name); //对象本身属性，对于RDP来说，是变更前的数据
							} else if(ATYPE_model.equals(type)) {//对象本身属性
								beforeValue = getValue(per, name);
							}//标准属性暂未涉及
							
							if(null != changeObj && changeObj.has(name)) {
								avo.setValue(TMUtil.conversion(changeObj.getString(name)));
							} else {
								avo.setValue(TMUtil.conversion(beforeValue));//天马配置上，物料扩展字段全部使用的是IBA属性
							}
							avo.setBeforeValue(TMUtil.conversion(beforeValue));
							analyzeConstraint(av, avo);
							
							// 指定属性不可编辑
							if(attrs.contains(name)) {
								avo.setStatus("2"); 
							}
							// 需要隐藏的内容 不返回
							if("0".equals(avo.getStatus()) || "1".equals(avo.getStatus())) {
								continue;
							}
							String resultObj = JSON.toJSONString(avo, true);
							array.put(new JSONObject(resultObj));
						}
					}
				}
			}
			
			//对象上的属性：从对象上拿属性，全部属性
//			TypeDefinitionReadView tv = TypeDefinitionServiceHelper.service.getTypeDefView(softType);
//			Collection<AttributeDefinitionReadView> allLays = tv.getAllAttributes();
//			for (AttributeDefinitionReadView lay : allLays) {
//				String name = lay.getName();
//				beforeValue = (String) IBAUtil.getIBAValue((IBAHolder) per, name); //对象本身属性，对于RDP来说，是变更前的数据
//				if(name.indexOf(".") < 0 ){ //属性中带.的，不考虑
//					//这种数据是类型上的属性，非业务属性，需要去掉
//					if("com.ptc.core.meta.common.TypeInstanceIdentifier".equals(tv.getAttributeByName(name).getDatatype().getName())) {
//						continue;
//					}
//					avo = new AttrRuleVo();
//					if(null != changeObj && changeObj.has(name)) {
//						avo.setValue(TMUtil.conversion(changeObj.getString(name)));
//					} else {
//						avo.setValue(TMUtil.conversion(beforeValue));//天马配置上，物料扩展字段全部使用的是IBA属性
//					}
//					avo.setBeforeValue(TMUtil.conversion(beforeValue));
//					analyzeConstraint(tv.getAttributeByName(name), avo);
//					if(StringUtils.isNotEmpty(avo.getName())) { //当存在属性名称时，才加入
//						String resultObj = JSON.toJSONString(avo, true);
//						array.put(new JSONObject(resultObj));
//					}
//				}
//			}
			
			//分类属性
			if(per instanceof WTPart) {
				ClassificationNode node = CSMUtil.getClassNodeByPart((WTPart) per);
				if(null != node) {
					ClassificationNodeDefaultView cndv=ClassificationObjectsFactory.newClassificationNodeDefaultView(node);
		    		cndv=ClassificationHelper.service.refreshClassificationNodeDefaultView(cndv);
		    		DefaultAttributeContainer dac = (DefaultAttributeContainer)cndv.getAttributeContainer();
					AttributeDefDefaultView avv[] = dac.getAttributeDefinitions();
//					AbstractValueView valueViews[] = dac.getAttributeValues();
					for (int i=0; i<avv.length; i++) {
						avo = new AttrRuleVo();
//						beforeValue = (String) IBAUtil.getInternalValue(valueViews[i]);//这个值取的好像不对
						beforeValue = (String) IBAUtil.getIBAValue((IBAHolder) per, avv[i].getName()); //分类属性
						if(null != changeObj && changeObj.has(avv[i].getName())) {
							avo.setValue(TMUtil.conversion(changeObj.getString(avv[i].getName())));
						} else {
							avo.setValue(TMUtil.conversion(beforeValue));//天马配置上，物料扩展字段全部使用的是IBA属性
						}
						avo.setBeforeValue(TMUtil.conversion(beforeValue));
						getClassAttrInfo(node, avv[i], avo);
						String resultObj = JSON.toJSONString(avo);
						array.put(new JSONObject(resultObj));
					}
				}
			}
		} catch (JSONException e) {
			e.printStackTrace();
			tip = e.getLocalizedMessage();
		} catch (CSMClassificationNavigationException e) {
			e.printStackTrace();
			tip = e.getLocalizedMessage(Locale.getDefault());
		} catch (RemoteException e) {
			e.printStackTrace();
			tip = e.getLocalizedMessage();
		} catch (WTException e) {
			e.printStackTrace();
			tip = e.getLocalizedMessage(Locale.getDefault());
		}
		return tip ;
	}
	
	/**
	 * 获取分类属性
	 * @param node
	 * @param attrName
	 * @param attrRuleVo
	 * @return
	 * @throws CSMClassificationNavigationException
	 * @throws RemoteException
	 * @throws WTException
	 * @author xucr
	 * @CreateDate 2020年11月26日
	 */
	public static AttrRuleVo getClassAttrInfo(ClassificationNode node,AttributeDefDefaultView avv, AttrRuleVo attrRuleVo) throws CSMClassificationNavigationException, RemoteException, WTException{
		String ibaName=avv.getName();
		String ibaLabel=avv.getLocalizedDisplayString();
		attrRuleVo.setName(ibaName);
		attrRuleVo.setDisplayName(ibaLabel);
//		attrRuleVo.setDataType(avv.getAttributeDefinitionClassName());
		attrRuleVo.setDataType(getDataType(avv.getAttributeDefinitionClassName()));
		attrRuleVo.setSource(ATTR_TYPE[1]);
		getClassAttrRule(node,avv,attrRuleVo);
		return attrRuleVo;
	}
	
	/**
	 * 返回数据类型
	 * @param dataType
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月8日
	 */
	public static String getDataType(String dataType) {
		/**
		 * 数据格式有两种类型，但不仅限String，还有Boolean、Float等
		 * 1、wt.iba.definition.StringDefinition
		 * 2、java.lang.String
		 */
		String result = dataType.substring(dataType.lastIndexOf(".") + 1);
		if(result.indexOf("Definition") > -1) {
			result = result.split("Definition")[0];
		}
		return result;
	}
	
	/**
	 * 分类属性规则
	 * @param node
	 * @param avv
	 * @param attrRuleVo
	 * @throws WTException
	 * @author xucr
	 * @CreateDate 2020年11月26日
	 */
	public static void getClassAttrRule(ClassificationNode node,AttributeDefDefaultView avv,AttrRuleVo attrRuleVo) throws WTException{
		QuerySpec select = new QuerySpec(CSMSingleDefConstraint.class);
		select.appendWhere(new SearchCondition(
				CSMSingleDefConstraint.class, "theAttributeDefReference.key.id", "=", avv.getObjectID().getId()), new int[] { 0 });
		select.appendAnd();
		select.appendWhere(new SearchCondition(
				CSMSingleDefConstraint.class, "theIBAHolderReference.key", "=", node.getPersistInfo().getObjectIdentifier()), new int[] { 0 });
		QueryResult qr = PersistenceHelper.manager.find((StatementSpec) select);
		while (qr.hasMoreElements()) {
			CSMSingleDefConstraint constraint = (CSMSingleDefConstraint) qr.nextElement();
			ValueConstraint valueConstraint = constraint.getValueConstraint();
			if (valueConstraint instanceof ValueRequired) {
				//要求值
				attrRuleVo.setRequired(true);
			}else if(valueConstraint instanceof SingleValued){
				//单值
				attrRuleVo.setSingleValued(true);
			}else if(valueConstraint instanceof StringContentDiscreteSet){
				//合法值字符串集
				StringContentDiscreteSet scds = (StringContentDiscreteSet) valueConstraint;
				Vector discreteSet = scds.getDiscreteSet();
				for(int i = 0;i<discreteSet.size();i++){
					attrRuleVo.getEnumMap().put(String.valueOf(discreteSet.elementAt(i)), String.valueOf(discreteSet.elementAt(i)));
				}
			}else if(valueConstraint instanceof IntegerContentRange){
				//整数范围
				//attrRuleVo.setIntRange((IntegerContentRange) valueConstraint);
				IntegerContentRange intRange = (IntegerContentRange) valueConstraint;
				attrRuleVo.getNumRange().add(Integer.parseInt(String.valueOf(intRange.getMinimum())));
				attrRuleVo.getNumRange().add(Integer.parseInt(String.valueOf(intRange.getMaximum())));
			}else if(valueConstraint instanceof IntegerContentDiscreteSet){
				//一组整数
				IntegerContentDiscreteSet scds = (IntegerContentDiscreteSet) valueConstraint;
				Vector discreteSet = scds.getDiscreteSet();
				for(int i = 0;i<discreteSet.size();i++){
					attrRuleVo.getEnumMap().put(String.valueOf(discreteSet.elementAt(i)), String.valueOf(discreteSet.elementAt(i)));
				}
			}else if(valueConstraint instanceof FloatContentRange){
				//实数范围
				FloatContentRange floatRange = (FloatContentRange) valueConstraint;
				attrRuleVo.getNumRange().add(Double.parseDouble(String.valueOf(floatRange.getMinimum())));
				attrRuleVo.getNumRange().add(Double.parseDouble(String.valueOf(floatRange.getMaximum())));
			} else if(valueConstraint instanceof FloatContentDiscreteSet) {
				//一组实数
				FloatContentDiscreteSet scds = (FloatContentDiscreteSet) valueConstraint;
				Vector discreteSet = scds.getDiscreteSet();
				Double[] doubleArray = new Double[discreteSet.size()];
				for(int i = 0;i<discreteSet.size();i++){
					doubleArray[i] = Double.parseDouble(String.valueOf(discreteSet.elementAt(i)));
					attrRuleVo.getEnumMap().put(String.valueOf(doubleArray[i]), String.valueOf(doubleArray[i]));
				}
			}
		}
	}
	
	/**
	 * 对象属性规则
	 * @param av 属性视图
	 * @param avo
	 * @author xucr
	 * @CreateDate 2020年11月26日
	 */
	public static void analyzeConstraint(AttributeDefinitionReadView av, AttrRuleVo avo) {
		if(null == avo) {
			avo = new AttrRuleVo();
		}
		PropertyValueReadView propertyValueView = av.getPropertyValueByName(PROP_DISPLAYNAME);
		if(null != propertyValueView) {
			String displayName = String.valueOf(
					null != propertyValueView.getValue(Locale.getDefault(), false) ? 
							propertyValueView.getValue(Locale.getDefault(), false) : propertyValueView.getValue());
			avo.setName(av.getName());
//			avo.setDataType(av.getDatatype().getName());
			avo.setDataType(getDataType(av.getDatatype().getName()));
			avo.setDisplayName(displayName);
		}
		avo.setSource(ATTR_TYPE[0]);
		for (ConstraintDefinitionReadView cons : av.getAllConstraints()) {
			if("com.ptc.core.meta.container.common.impl.SuggestedValuesConstraint".equals(cons.getRule().getRuleClassname())) {//建议值
				if (cons.getRuleDataObj() != null && cons.getRuleDataObj().getRuleData() instanceof DiscreteSet) {
					DiscreteSet dataSet = (DiscreteSet) cons.getRuleDataObj().getRuleData();
					Object[] els = dataSet.getElements();
					for (Object el : els) {
//						avo.getValueList().add(String.valueOf(el));
						avo.getEnumMap().put(String.valueOf(el), String.valueOf(el));
					}
				}else if(cons.getRule().getKey()!=null && 
						cons.getRule().getKey().contains("com.ptc.core.lwc.server.LWCEnumerationBasedConstraint") && 
						cons.getRuleDataObj()!=null){
					Collection<EnumerationEntryReadView> coll=cons.getRuleDataObj().getEnumDef().getAllEnumerationEntries().values();
					for(EnumerationEntryReadView eerv:coll){
						avo.getEnumMap().put(eerv.getName(),eerv.getPropertyValueByName(PROP_DISPLAYNAME).getValueAsString());
					}
				}
			}
			else if ("com.ptc.core.meta.container.common.impl.DiscreteSetConstraint".equals(cons.getRule().getRuleClassname())) {//合法值
				if (cons.getRuleDataObj() != null && cons.getRuleDataObj().getRuleData() instanceof DiscreteSet) {
					DiscreteSet dataSet = (DiscreteSet) cons.getRuleDataObj().getRuleData();
					Object[] els = dataSet.getElements();
					for (Object el : els) {
//						avo.getValueList().add(String.valueOf(el));
						avo.getEnumMap().put(String.valueOf(el), String.valueOf(el));
					}
				}else if(cons.getRule().getKey()!=null && 
						cons.getRule().getKey().contains("com.ptc.core.lwc.server.LWCEnumerationBasedConstraint") && 
						cons.getRuleDataObj()!=null){//枚举
					Collection<EnumerationEntryReadView> coll=cons.getRuleDataObj().getEnumDef().getAllEnumerationEntries().values();
					for(EnumerationEntryReadView eerv:coll){
						avo.getEnumMap().put(eerv.getName(),eerv.getPropertyValueByName(PROP_DISPLAYNAME).getValueAsString());
					}
				}
			}
			else if ("com.ptc.core.meta.container.common.impl.SingleValuedConstraint".equals(cons.getRule().getRuleClassname())) {//是否单值
				avo.setSingleValued(true);
			}
			else if ("com.ptc.core.meta.container.common.impl.ValueRequiredConstraint".equals(cons.getRule().getRuleClassname())) {//是否必须
				avo.setRequired(true);
			}
			else if ("com.ptc.core.meta.container.common.impl.StringLengthConstraint".equals(cons.getRule().getRuleClassname()) 
					|| "com.ptc.core.meta.container.common.impl.RangeConstraint".equals(cons.getRule().getRuleClassname())) {//有效范围
				if (cons.getRuleDataObj() != null
						&& cons.getRuleDataObj().getRuleData() instanceof com.ptc.core.meta.common.AnalogSet) {
					com.ptc.core.meta.common.AnalogSet aset = (com.ptc.core.meta.common.AnalogSet) cons.getRuleDataObj().getRuleData();
					if (null != aset.getRanges()) {
						Range range = aset.getRanges()[0];
						Integer length = ((Number) range.getUpperBoundValue()).intValue();
						avo.setLength(length);
					}
				}
			}
			else if (cons.getRule()!=null && LWCFilterBasedConstraint.class.getName().equals(cons.getRule().getDefClassname())) {//是否显示、可编辑
				Object filter = cons.getFilter();
				if (filter !=null && filter instanceof ScreenDefinitionReadView) {
//					ScreenDefinitionReadView sdr = (ScreenDefinitionReadView)filter;
//					OperationIdentifier opId = sdr.getOperationId();
					PropertyValueReadView pvrv=cons.getRule().getPropertyValueByName(PROP_DISPLAYNAME);
					String v="3"; //读写
					if(pvrv!=null){
						String pvrVal=(String)pvrv.getValue();
                        if("Hidden".equalsIgnoreCase(pvrVal)){
                            v="0";
						}else if("Value Hidden".equalsIgnoreCase(pvrVal)){
							v="1";
						}else if("Immutable".equalsIgnoreCase(pvrVal)){
							v="2";
						}
					}
					avo.setStatus(v);
				}
			}
		}
	}
	
	/**
	 * 获取对象软类型
	 * @param persistable
	 * @return
	 * @author xucr
	 * @CreateDate 2020年11月26日
	 */
	public static String getSoftTypeName(Persistable persistable){
		String type = TypedUtility.getTypeIdentifier(persistable).getTypename();
		return type.substring(type.lastIndexOf("|")+1, type.length());
	}
	
	/**
	 * 获取对象软类型
	 * @param persistable 对象
	 * @param endsWith 是否返回最底层类型
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月11日
	 */
	public static String getSoftTypeName(Persistable persistable, boolean endsWith){
		String type = TypedUtility.getTypeIdentifier(persistable).getTypename();
		if(endsWith) {
			type = type.substring(type.lastIndexOf("|")+1, type.length());
		}
		return type;
	}
	
	/**
	 * 获取类型的子类型
	 * @param softType
	 * @return
	 * @author xucr
	 * @CreateDate 2020年11月28日
	 */
	public static List<TypeDefinitionReference> getChildTypeDefinition(String parentSottKey)  {
		List<TypeDefinitionReference> childSoftType = new ArrayList<TypeDefinitionReference>();
		try {
			TypeDefinitionReadView view = TypeDefinitionServiceHelper.service.getTypeDefView(parentSottKey);
			Set<TypeDefinitionReadView> set = TypeDefinitionServiceHelper.service.getChildTypeDefViews(view);
			TypeDefinitionReference clientType = null;
			for(TypeDefinitionReadView readView : set) {
				clientType = ClientTypedUtility.getTypeDefinitionReference(readView.getName());
				childSoftType.add(clientType);
			}
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (NotAuthorizedException e) {
			e.printStackTrace();
		} catch (WTContainerException e) {
			e.printStackTrace();
		} catch (WTException e) {
			e.printStackTrace();
		}
		return childSoftType;
	}
	
	/**
	 * 获取类型的子类型BranchId
	 * @param parentSottTypes 父项类型集合
	 * @param isContainParent 是否包含父项
	 * @return
	 * @author xucr
	 * @CreateDate 2020年11月28日
	 */
	public static List<Long> getChildTypeBranchId(String [] parentSottTypes, boolean isContainParent) {
		List<Long> ids = new ArrayList<Long>();
		if(null != parentSottTypes) {
			try {
				List<TypeDefinitionReference> childSoftType = null;
				TypeDefinitionReference parentSoftType = null;
				for(String parentSottType : parentSottTypes) {
					if(isContainParent) {
						parentSoftType = ClientTypedUtility.getTypeDefinitionReference(parentSottType);
						ids.add(parentSoftType.getKey().getBranchId());
					}
					childSoftType = getChildTypeDefinition(parentSottType);
					if(null != childSoftType && childSoftType.size() > 0) {
						for(int i = 0 ; i < childSoftType.size(); i++) {
							ids.add(childSoftType.get(i).getKey().getBranchId());
						}
					}
				}
			} catch (RemoteException e) {
				e.printStackTrace();
			} catch (WTException e) {
				e.printStackTrace();
			}
		}
		return ids;
	}
	
	/**
	 * 得到属性类型：IBA、MBA、对象属性
	 * @param mv
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月16日
	 */
	private static String attrType(AttributeDefinitionReadView mv) {
		String clsName = mv.getAttributeTypeIdentifier().getClass().getName();
		if (clsName.contains("NonPersistedAttributeTypeIdentifier")) {
			return ATYPE_ref;// folder.id 这种
		} else if (clsName.contains("ServerCalculatedAttributeTypeIdentifier")) {
			return ATYPE_mapping; // 安全标签，映射关系这种
		} else if (clsName.contains("ModeledAttributeTypeIdentifier")) {
			if (mv.getAttributeTypeIdentifier().getAttributeName().contains(".")) {
				return ATYPE_basic;// 扩列
			}
			return ATYPE_model; // 对象本身属性
		} else if (clsName.contains("InstanceBasedAttributeTypeIdentifier")) {
			return ATYPE_iba;
		}
		return null;
	}
	
	/**
	 * 获取jsonObject中str的值
	 * @param json
	 * @param str
	 * @return
	 * @throws JSONException
	 * @author xucr
	 * @CreateDate 2020年12月5日
	 */
	public static String getJSONString(JSONObject json, String str) throws JSONException {
		String result = "";
		if(null != json && StringUtils.isNotEmpty(str)) {
			if(json.has(str)) {
				result = json.getString(str);
			}
		}
		return result;
	}
	
	/**
	 * 获取对象本身属性
	 * @param per 对象
	 * @param name 本身属性名称
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月16日
	 */
	public static String getValue(Persistable per, String name) {
		String value = "";
		//将第一个字符变为大写
		String method = "get" + name.substring(0,1).toUpperCase() + name.substring(1, name.length());
		Object o = getAttributeObjValForReflex(per, method);
		if(null != o) {
			value = o.toString();
		}
		return value;
	}
	
	/**
	 * 通过反射获取对象方法
	 * @param object
	 * @param methodName
	 * @return
	 * @author xucr
	 * @CreateDate 2020年12月16日
	 */
	public static Object getAttributeObjValForReflex(Object object, String methodName) {
		Object value = "";
		if (object != null) {
			try {
				Class classObj = object.getClass();
				Method method = classObj.getMethod(methodName, new Class[0]);
				value = method.invoke(object, new Object[0]);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return value;
	}
	
	public static Blob str2Blob(String str) {
		Blob blob = null;
		try  {
			ByteArrayOutputStream out = new  ByteArrayOutputStream();
            ObjectOutputStream outputStream = new  ObjectOutputStream(out);
            outputStream.writeObject(str);
            byte [] bytes  =  out.toByteArray();
            outputStream.close();
            blob= new SerialBlob(bytes);
        }  catch  (Exception e) {
            e.printStackTrace();
        }
		return blob;
	}
	
	/**
	 * BLOB转成list
	 * @param blob
	 * @return
	 * @throws IOException
	 */
	public static String blob2str(Blob blob){
		String str = "";
		try  {
            ObjectInputStream in  = new ObjectInputStream(blob.getBinaryStream());
            str = (String) in.readObject();
            in.close();   
        }  catch  (Exception e) {
            e.printStackTrace();
        }
		return str;
	}
	
	/**
	 * 配置设计视图规范
	 * @param viewName
	 * @return
	 * @throws ViewException
	 * @throws WTException
	 * @throws WTPropertyVetoException
	 * @author xucr
	 * @CreateDate 2021年1月27日
	 */
	public static WTPartStandardConfigSpec getConfigSpecByView(String viewName)
			throws ViewException, WTException, WTPropertyVetoException {
		View viewObj = ViewHelper.service.getView(viewName);
		WTPartStandardConfigSpec standardConfig = WTPartHelper.service.findWTPartConfigSpec().getStandard();
		standardConfig.setView(viewObj);
		return standardConfig;
	}
	
	/**
	 * 获取BOM直接子项
	 * @param part
	 * @throws ViewException
	 * @throws WTPropertyVetoException
	 * @throws WTException
	 * @author xucr
	 * @throws JSONException 
	 * @CreateDate 2021年1月27日
	 */
	public static JSONObject getChildren(WTPart part) throws ViewException, WTPropertyVetoException, WTException, JSONException {
		WTPartStandardConfigSpec spec = getConfigSpecByView(part.getViewName());
		QueryResult qs = WTPartHelper.service.getUsesWTParts(part, spec);
		JSONArray children = new JSONArray();
		JSONObject obj = null;
		String version = "";
		String view = "";
		String number = "";
		while (qs.hasMoreElements()) {
			obj = new JSONObject();
			Persistable[] apersistable = (Persistable[]) qs.nextElement();
			WTPart childpart = (WTPart) apersistable[1];//子项
			version = CommonPDMUtil.getVersion(childpart);
			view = childpart.getViewName();
			number = childpart.getNumber();
			
			obj.put("partNum", number);
			obj.put("version", version);
			obj.put("view", view);
			children.put(obj);
		}
		//父项
		JSONObject data = new JSONObject();
		data.put("partNum", part.getNumber());
		data.put("version", CommonPDMUtil.getVersion(part));
		data.put("view", part.getViewName());
		data.put("children", children);
		
		//封装
		return data;
	}
	
	/**
	 * 获取特定替代料
	 * @param bomPart
	 * @param mainPart
	 * @return
	 * @throws WTRuntimeException
	 * @throws WTException
	 * @throws JSONException
	 * @author xucr
	 * @CreateDate 2021年1月27日
	 */
	public static JSONArray getSubstitutes(WTPart bomPart, WTPart mainPart) throws WTRuntimeException, WTException, JSONException {
		JSONArray array = new JSONArray();
		QueryResult qr = PersistenceHelper.manager.find(
				WTPartUsageLink.class,bomPart,"usedBy", (WTPartMaster)(mainPart.getMasterReference().getObject()));//使用关系
		JSONObject obj = null;
		while(qr.hasMoreElements()) {
			WTPartUsageLink link2 = (WTPartUsageLink) qr.nextElement();
			QueryResult qr1 = WTPartHelper.service.getSubstitutesWTPartMasters(link2);
			while(qr1.hasMoreElements()){
				obj = new JSONObject();
				WTPartMaster subPartMaster = (WTPartMaster) qr1.nextElement();
				obj.put("partNum", subPartMaster.getNumber());
				obj.put("partName", subPartMaster.getName());
				array.put(obj);
			}
		}
		return array;
	}
}
